﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using RayDen.Library.Core.Primitives;

namespace RayDen.Library.Core
{

    public class Geometry
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static float G(ref Point v1HitPoint, ref Point v2HitPoint, ref Normal v1GeoNormal, ref Normal v2GeoNormal)
        {
            Vector w = (v2HitPoint - v1HitPoint).Normalize();
            Vector mw = -w;
            return Normal.AbsDot(ref v1GeoNormal, ref  w) * Normal.AbsDot(ref v2GeoNormal, ref mw) / MathLab.DistanceSquared(ref v1HitPoint, ref v2HitPoint);
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static Vector Reflect(ref Vector dir, ref Normal N)
        {
            float dp = Normal.Dot(ref N, ref dir);
            return dir - (2f*dp)*N.ToVec();
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static float EuclidianDistance(ref Vector p1, ref Vector p2)
        {
            return MathLab.Sqrt(((p1.x-p2.x) * (p1.x-p2.x) + (p1.y-p2.y) * (p1.y-p2.y) + (p1.z-p2.z) * (p1.z-p2.z)));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static float EuclidianDistance(ref Vector p1, ref Point p2)
        {
            return MathLab.Sqrt(((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y) + (p1.z - p2.z) * (p1.z - p2.z)));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static float EuclidianDistance(ref Point p1, ref Point p2)
        {
            return MathLab.Sqrt(((p1.x-p2.x) * (p1.x-p2.x) + (p1.y-p2.y) * (p1.y-p2.y) + (p1.z-p2.z) * (p1.z-p2.z)));
        }

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static int ClassifyDirection(ref Vector dir)
        {
            var xs = Math.Sign(dir.x)+1;
            var ys = Math.Sign(dir.y)+1;
            var zs = Math.Sign(dir.z)+1;

            return xs | (ys << 2) | (zs << 4);
        }

        public static void RandomVector(float u0, float u1, out Vector v)
        {
            var t1 = MathLab.M_2PI*u0;
            var t2 = 2.0f*u1 - 1.0f;
            var s = MathLab.Sin(t1);
            var c = MathLab.Cos(t1);
            var t = MathLab.Sqrt(1.0f - t2*t2);
            v = new Vector(s*t,t2,c*t);
        }
    }
}
